This document is a first attempt to quantitatively compare gestures made using the Gepeto app with their corresponding reference gestures. Following the model of d’allessandro et al 2011, we use Pearson’s correlation and Root Mean Square Error (RMSE) are computed. Results are presented along with plots of the gesture scaled to and overlaid with its reference. Audio of both are also included.

The original paper weighed the correlation and RMSE with the signal power. For simplicity, I am not doing that for now, but results still seem ok. The original paper also used dynamic time warping to modify signals of uneven lengths. I am just doing a linear scaling, which does not warp the rhythm of the signal. It is important to retain the actual rhythm of the gesture because the correct pronunciation of the corpus phrases depend on correct rhythm.

Right now, I’m only comparing the output f0 curves without taking into consideration where the syllables are. For some gestures that sound distorted yet still have high scores, taking rhythm into account should yield more accurate scores.

1 Helper functions for evenly spaced curve

Both correlation and RMSE take two time series as input. Therefore, it is necessary to convert both the reference pitch curve and gestures from the Gepeto interface into time series data.

The following is a function that takes a tibble with unevenly spaced points of frequency data (on a 0 to 1 scale) and converts it to a tibble with a certain number of evenly spaced points whose values are interpolated from the original data.

2 Loading reference pitch curves

References contain information about the stylized pitch curve of a phrase. The stylization is done by Prosogram, an extension to Praat based on a perceptual model detailed by d’Allessandro and Mertens 1995. The stylization is originally generated as PitchTier files by Prosogram but are converted to JSON by Script 3: pitchtierToJSON.

The code below loads all the available reference files but only looks at the first one as a test.

2.1 Loading all phrases

Now let’s do the same thing to all the reference files

# Original data for each reference, in terms of:
# percent : percentage time (i.e. scrub)
# f : frequency in ST with 130 hz reference
ref_originals <- lapply(ref_filenames, function(elt) {
  result <- fromJSON(paste0(path,"prosogram_pt/", elt)) %>% as_tibble() %>% 
            # To avoid confusion, create new column called percent
            mutate(percent = scrub) %>% select(percent, f)
})

# Interpolated time series data of just the f values
ref_tss <- lapply(ref_originals, function(elt) {
  ref_interp<-get_interpolated_data(elt, num_samples)
  ref_interp$value
})

# A vector with just the names of the phrases (w/o .json extension)
ref_phrases <- do.call("rbind", lapply(ref_filenames, function(elt) {
  str_split(elt, '.json')[[1]][1]
}))[,1]

# Returns the reference time series f values given the phrase name
get_ref_ts <- function(phrase_name) {
  index <- match(phrase_name, ref_phrases)
  if (is.na(index)) { return(NULL) }
  return(ref_tss[[index]])
}

3 Loading gestures

The gestures are collected from non-native speakers enrolled in a class on French rhythm and intonation. First, just load and plot one gesture as a test.

The resulting gesture is plotted with its reference overlaid. In this analysis, the phonemes of the gesture are not aligned with those of the reference. It’s

3.1 Loading all gestures

Now, convert all the gestures into time series.

# Original data for each gesture, in terms of:
# percent : percentage time (i.e. scrub)
# f : frequency in ST with 130 hz reference
gest_originals <- lapply(gest_filenames, function(elt) {
  result <- fromJSON(paste0(path, elt)) %>% as_tibble() %>% 
    # NOTE THIS EXTRA STEP      
    prep_gest()
})

# Interpolated time series data of just the f values
gest_tss <- lapply(gest_originals, function(elt) {
  gest_interp<-get_interpolated_data(elt, num_samples)
  gest_interp$value
})

# Returns the gesture time series f values given the phrase name
get_gest_ts <- function(gest_name) {
  index <- match(gest_name, gests)
  if (is.na(index)) { return(NULL) }
  return(gest_tss[[index]])
}

4 Testing comparison functions

Now we are ready to quantitatively compare a gesture and its reference. One method is Pearson’s Correlation, which check’s the similarity between the two curves. A value of 1 means identical curves. Note that the mean is subtracted from each curve, so larger gaps between the curves should not decrease the correlation value.

\(r = \frac{{}\sum_{i=1}^{n} (x_i - \overline{x})(y_i - \overline{y})} {\sqrt{\sum_{i=1}^{n} (x_i - \overline{x})^2(y_i - \overline{y})^2}}\)

Another method is Root Mean Square Error (RMS), which meansures the dissiminlarity between the two curves. The higher the number means there is more difference.

$ RMS = $

In the 2011 paper evaluating chironomy, both of these measures are weighed by the intensity of the reference audio. For now I’m leaving that weighting out.

cor(ref_ts, gest_ts,  method = "pearson")
[1] 0.493454
rmse <- function(a, b) {
  return(sqrt(sum( ((a-mean(a)) - (b-mean(b))) ^2 )))
}

rmse(ref_ts, gest_ts)
[1] 42.37105

4.1 Calculating comparison functions for all gestures


# A vector with just the names of the phrases (w/o .json extension)
gests <- do.call("rbind", lapply(gest_filenames, function(elt) {
  str_split(elt, '.gest')[[1]][1]
}))[,1]

# Just the name of subjects
gest_subjects <- do.call("rbind", lapply(gests, function(elt) {
  tail(str_split(elt, '-')[[1]], 1)
}))[,1]
# Just the name of phrases
gest_phrases <- do.call("rbind", lapply(gests, function(elt) {
  str_split(elt, '-')[[1]]
}))[,1]

# Extract the reference phrase from the whole gesture name
get_ref_name <- function(gest_name) {
  return(str_split(gest_name, '-')[[1]][1])
}

# Compute the correlatoin and rms given the entire gesture name
get_corr <- function(gest_name) {
  ref_ts <- get_ref_ts(get_ref_name(gest_name))
  gest_ts <- get_gest_ts(gest_name)
  return(cor(ref_ts, gest_ts, method="pearson"))
}

get_rms <- function(gest_name) {
  ref_ts <- get_ref_ts(get_ref_name(gest_name))
  gest_ts <- get_gest_ts(gest_name)
  return(rmse(ref_ts, gest_ts))
}

corr_all <- do.call("rbind", lapply(gests, function(elt) {
  get_corr(elt)
}))[,1]

rmse_all <- do.call("rbind", lapply(gests, function(elt) {
  get_rms(elt)
}))[,1]

# Combine the above vectors into a tibble
gest_tibble <- tibble(gest=gests, corr=corr_all, rmse=rmse_all)
print(as.matrix(gest_tibble), quote = FALSE)
      gest                                       corr        rmse    
 [1,] 1_Il_nait_tres_premature-a_c                0.49345403 42.37105
 [2,] 1_Il_nait_tres_premature-b_m                0.77186565 32.54695
 [3,] 10_jean_saigne_beaucoup-a_m                -0.37965230 36.67639
 [4,] 10bis_jenseigne_beaucoup-l1                 0.41159391 23.43155
 [5,] 10bis_jenseigne_beaucoup-l2                 0.77562055 17.50671
 [6,] 13_la_belle_ferme_le_voile-c1               0.76059930 29.17405
 [7,] 13_la_belle_ferme_le_voile-c2               0.93557979 16.69488
 [8,] 13bis_la_belle_ferme__le_voile-g1           0.85223163 26.02876
 [9,] 13bis_la_belle_ferme__le_voile-g2           0.92521216 15.35320
[10,] 1bis_Il_naitrait_premature-a_y             -0.26542755 43.33155
[11,] 1bis_Il_naitrait_premature-b_g              0.85193229 25.67243
[12,] 2_tu_parais_tres_soucieux-a_c               0.73495035 32.21343
[13,] 2_tu_parais_tres_soucieux-b_s               0.91186830 21.97501
[14,] 20_jean_pierre_et_jacques-s1               -0.05181063 54.16585
[15,] 20_jean_pierre_et_jacques-s2                0.54297527 39.86701
[16,] 20_jean_pierre_et_jacques-s3                0.59164138 37.16551
[17,] 20bis_jeanpierre_et_jacques-y1             -0.06930822 35.38395
[18,] 20bis_jeanpierre_et_jacques-y2              0.74905564 23.81674
[19,] 27_la_bonne__cuisine_avec_des_navets-v1     0.41059865 43.34267
[20,] 27_la_bonne__cuisine_avec_des_navets-v2     0.79152527 30.19718
[21,] 27_la_bonne__cuisine_avec_des_navets-v3     0.61458470 40.98867
[22,] 27bis_la_bonne_cuisine__avec_des_navets-m1  0.82886586 24.10916
[23,] 27bis_la_bonne_cuisine__avec_des_navets-m2  0.83839011 27.22726
[24,] 27bis_la_bonne_cuisine__avec_des_navets-m3  0.76041101 28.90396
[25,] 2bis_tu_paraitrais_soucieux-a_g             0.68682280 24.70003
[26,] 2bis_tu_paraitrais_soucieux-b_y             0.38597443 31.00174

4.2 Plotting

Let see if our numbers make sense. In Christophe’s previous evaluation, they primarily looked at the correlation value and only looked at the RMS if the correlation was the same for two stimuli.


plot_gest_and_ref <- function(gest_name) {
  ref_phrase <- get_ref_name(gest_name)
  ref_ts <- get_ref_ts(ref_phrase)
  gest_ts <- get_gest_ts(gest_name)
  
  row <- filter(gest_tibble, gest==gest_name)
  corr <- round(row$corr, 4)
  rmse <- round(row$rmse, 4)
  
  my_data <- tibble(gest=gest_ts, ref=ref_ts, percent=seq(0, 1, length.out=num_samples))
  
  my_plot <- ggplot(data=my_data, aes(x=percent, y=gest, color="gesture")) +
    scale_color_discrete(name = "Data source") +
    geom_point(size=0.5) +
    geom_point(data=my_data, aes(x=percent, y=ref, color="reference"), size=0.5) +
    labs(title=paste(gest_name, "with its reference"), 
            subtitle=paste("Corr:", corr, "RMSE:", rmse),
            y="frequency (semitones from 130hz)",
            x="percent time")
  return(my_plot)
}

# Plot everything and store plots in a list
plots_all<-lapply(gests, plot_gest_and_ref)

Now, let’s divide the gestures by score ranges and plot them. There are some exceptions for the mid values, but in general, the highest scoring gestures are the most accurate and the lowest scoring the least accurate.

4.2.1 Highest scoring gestures (> 0.9)

Gesture Original

A visual guide was displayed for this trial.


Gesture Original

A visual guide was displayed for this trial.


Gesture Original

A visual guide was not displayed for this trial. This one is unmistakably pronouncing the correct phrase, but it sounds like it has a bit of an accent.


4.2.2 Highish scores (.7 to .9)

plots_all[[2]]

Gesture Original

Sounds correct to me.


plots_all[[5]]

Gesture Original

Sounds correct to me.


plots_all[[11]]

Gesture Original

Sounds correct but a bit odd.


plots_all[[12]]

Gesture Original

Sounds correct but the rhythm is quite off


plots_all[[18]]

Gesture Original

Sounds correct to me.


plots_all[[20]]

Gesture Original

Sounds correct to me.


plots_all[[23]]

Gesture Original

Sounds a bit weird with rhythm in the end.


plots_all[[24]]

Gesture Original

Sounds correct to me.


4.2.3 Midish scores (.5 to .7)

plots_all[[15]]

Gesture Original

With visual guide. Sounds correct to me.


plots_all[[16]]

Gesture Original

With visual guide. Sounds correct.


plots_all[[21]]

Gesture Original

With visual guide. Sounds a bit ambiguous.


plots_all[[25]]

Gesture Original

Without visual guide. Most likely correct but could be a bit ambiguous.


4.2.4 Lowish scores (.3 to .5)

plots_all[[1]]

Gesture Original

Without visual guide. Sounds correct to me.


plots_all[[4]]

Gesture Original

Without visual guide. Could be heard as correct phrase but ambiguous.


plots_all[[19]]

Gesture Original

Without visual guide. Sounds very ambiguous.


plots_all[[26]]

Gesture Original

Without visual guide. Sounds incorrect or ambiguous.


4.2.5 Lowest scores(< 0)

plots_all[[3]]
Gesture Original

A visual guide was not displayed for this trial. The gesture sounds like the other meaning of the phrase.


plots_all[[10]]
Gesture Original

A visual guide was not displayed for this trial. I think this would still be heard as the correct phrase, but its intonation deviates enormously from the target.


plots_all[[17]]
Gesture Original

A visual guide was not displayed for this trial. The gesture sounds quite ambiguous. Could sometimes get heard incorrectly.


plots_all[[14]]
Gesture Original

A visual guide was not displayed for this trial. Despite the low correlation score, I think this phrase would probably be heard correctly.


LS0tCnRpdGxlOiAiQ29tcGFyZSBHZXN0dXJlIgphdXRob3I6ICJYaWFvIFhpYW8iCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIgCm91dHB1dDogCiAKIGh0bWxfbm90ZWJvb2s6CiAgICBkZXB0aDogNAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICB0b2M6IHllcwogaHRtbF9kb2N1bWVudDoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHllcwotLS0KClRoaXMgZG9jdW1lbnQgaXMgYSBmaXJzdCBhdHRlbXB0IHRvIHF1YW50aXRhdGl2ZWx5IGNvbXBhcmUgZ2VzdHVyZXMgbWFkZSB1c2luZyB0aGUgR2VwZXRvIGFwcCB3aXRoIHRoZWlyIGNvcnJlc3BvbmRpbmcgcmVmZXJlbmNlIGdlc3R1cmVzLiBGb2xsb3dpbmcgdGhlIG1vZGVsIG9mIGQnYWxsZXNzYW5kcm8gZXQgYWwgMjAxMSwgd2UgdXNlIFBlYXJzb24ncyBjb3JyZWxhdGlvbiBhbmQgUm9vdCBNZWFuIFNxdWFyZSBFcnJvciAoUk1TRSkgYXJlIGNvbXB1dGVkLiBSZXN1bHRzIGFyZSBwcmVzZW50ZWQgYWxvbmcgd2l0aCBwbG90cyBvZiB0aGUgZ2VzdHVyZSBzY2FsZWQgdG8gYW5kIG92ZXJsYWlkIHdpdGggaXRzIHJlZmVyZW5jZS4gQXVkaW8gb2YgYm90aCBhcmUgYWxzbyBpbmNsdWRlZC4KClRoZSBvcmlnaW5hbCBwYXBlciB3ZWlnaGVkIHRoZSBjb3JyZWxhdGlvbiBhbmQgUk1TRSB3aXRoIHRoZSBzaWduYWwgcG93ZXIuIEZvciBzaW1wbGljaXR5LCBJIGFtIG5vdCBkb2luZyB0aGF0IGZvciBub3csIGJ1dCByZXN1bHRzIHN0aWxsIHNlZW0gb2suIFRoZSBvcmlnaW5hbCBwYXBlciBhbHNvIHVzZWQgZHluYW1pYyB0aW1lIHdhcnBpbmcgdG8gbW9kaWZ5IHNpZ25hbHMgb2YgdW5ldmVuIGxlbmd0aHMuIEkgYW0ganVzdCBkb2luZyBhIGxpbmVhciBzY2FsaW5nLCB3aGljaCBkb2VzIG5vdCB3YXJwIHRoZSByaHl0aG0gb2YgdGhlIHNpZ25hbC4gSXQgaXMgaW1wb3J0YW50IHRvIHJldGFpbiB0aGUgYWN0dWFsIHJoeXRobSBvZiB0aGUgZ2VzdHVyZSBiZWNhdXNlIHRoZSBjb3JyZWN0IHByb251bmNpYXRpb24gb2YgdGhlIGNvcnB1cyBwaHJhc2VzIGRlcGVuZCBvbiBjb3JyZWN0IHJoeXRobS4KClJpZ2h0IG5vdywgSSdtIG9ubHkgY29tcGFyaW5nIHRoZSBvdXRwdXQgZjAgY3VydmVzIHdpdGhvdXQgdGFraW5nIGludG8gY29uc2lkZXJhdGlvbiB3aGVyZSB0aGUgc3lsbGFibGVzIGFyZS4gRm9yIHNvbWUgZ2VzdHVyZXMgdGhhdCBzb3VuZCBkaXN0b3J0ZWQgeWV0IHN0aWxsIGhhdmUgaGlnaCBzY29yZXMsIHRha2luZyByaHl0aG0gaW50byBhY2NvdW50IHNob3VsZCB5aWVsZCBtb3JlIGFjY3VyYXRlIHNjb3Jlcy4KCiMgSGVscGVyIGZ1bmN0aW9ucyBmb3IgZXZlbmx5IHNwYWNlZCBjdXJ2ZQoKQm90aCBjb3JyZWxhdGlvbiBhbmQgUk1TRSB0YWtlIHR3byB0aW1lIHNlcmllcyBhcyBpbnB1dC4gVGhlcmVmb3JlLCBpdCBpcyBuZWNlc3NhcnkgdG8gY29udmVydCBib3RoIHRoZSByZWZlcmVuY2UgcGl0Y2ggY3VydmUgYW5kIGdlc3R1cmVzIGZyb20gdGhlIEdlcGV0byBpbnRlcmZhY2UgaW50byB0aW1lIHNlcmllcyBkYXRhLgoKVGhlIGZvbGxvd2luZyBpcyBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSB0aWJibGUgd2l0aCB1bmV2ZW5seSBzcGFjZWQgcG9pbnRzIG9mIGZyZXF1ZW5jeSBkYXRhIChvbiBhIDAgdG8gMSBzY2FsZSkgYW5kIGNvbnZlcnRzIGl0IHRvIGEgdGliYmxlIHdpdGggYSBjZXJ0YWluIG51bWJlciBvZiBldmVubHkgc3BhY2VkIHBvaW50cyB3aG9zZSB2YWx1ZXMgYXJlIGludGVycG9sYXRlZCBmcm9tIHRoZSBvcmlnaW5hbCBkYXRhLgoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoInpvbyIpCmxpYnJhcnkoInRpbWV0ayIpCmxpYnJhcnkoInRpZHl2ZXJzZSIpCmxpYnJhcnkoImpzb25saXRlIikKCiMgVG8gc2VlIGV2ZXJ5dGhpbmcgd2hpbGUgZGVidWdnaW5nCm9wdGlvbnModGliYmxlLnByaW50X21heCA9IEluZikKCiMgYXJnczogZGF0YSAtIHRpYmJsZSB3aXRoIGNvbHVtbnM6IHBlcmNlbnQgKCUgb2Ygd2F5IHRocm91Z2ggc2lnbmFsKSAmIGYgKGZyZXF1ZW5jeSBhdCB0aGF0IHBvaW50KSwgCiMgbnVtX3NhbXBsZXMgLSAjIGVxdWFsbHkgc3BhY2VkIHBvaW50cyBpbiBvdXRwdAojIHJldHVybnM6IHRpYmJsZSB3aXRoIGNvbHV1bW5zIGluZGV4ICYgdmFsdWUuIGluZGV4IGhhcyBudW1fc2FtcGxlcyBlcXVhbGx5IHNwYWNlZCBwb2ludHMgZnJvbSAwIHRvIDEKIyB2YWx1ZXMgYXJlIGludGVycGxvbGF0ZWQgZnJvbSBmCmdldF9pbnRlcnBvbGF0ZWRfZGF0YSA8LSBmdW5jdGlvbihkYXRhLCBudW1fc2FtcGxlcykgewogICMgQWRkIGVuZCBwb2ludHMgYXQgMCBhbmQgMSBpZiB0aGV5IGRvbid0IGFscmVhZHkgZXhpc3QsIGR1cGxpY2F0aW5nIGZpcnN0IGFuZCBsYXN0IGF2YWlsYWJsZSBmIHZhbHVlCiAgaWYgKCEgMCAlaW4lIGRhdGEkcGVyY2VudCkgewogICAgZGF0YSA8LSBhZGRfcm93KGRhdGEsIHBlcmNlbnQ9MCwgZj1kYXRhJGZbMV0sIC5iZWZvcmU9MSkKICB9CiAgaWYgKCEgKDEgJWluJSBkYXRhJHBlcmNlbnQpKSB7CiAgICBkYXRhIDwtIGFkZF9yb3coZGF0YSwgcGVyY2VudD0xLCBmPXRhaWwoZGF0YSRmLCAxKSkKICB9CiAgICAgICAgICAKICAjIENyZWF0ZSBhIHRpYmJsZSB3aXRoIGFsbCB0aGUgcG9pbnRzIHdlIGFyZSBpbnRlcmVzdGVkIGluLCB3aXRoIE5BIHZhbHVlcwogIHNhbXBsZV9wb2ludHMgPC0gdGliYmxlKHBlcmNlbnQ9c2VxKDAsIDEsIGxlbmd0aC5vdXQ9bnVtX3NhbXBsZXMpLCBmPU5BKSAKICAKICAjIEFkZCBhbGwgdGhlIHNhbXBsZSBwb2ludHMgd2hvc2Ugc2NydWIgdmFsdWUgZG9lc24ndCBhbHJlYWR5IGV4aXN0IGluIGRhdGEKICBkYXRhMiA8LSBiaW5kX3Jvd3MoZGF0YSwgZmlsdGVyKHNhbXBsZV9wb2ludHMsICEocGVyY2VudCAlaW4lIGRhdGEkcGVyY2VudCkpKSAgJT4lCiAgICAjIFRoZW4gc29ydCBieSBzY3J1YiBjb2x1bW5zICAKICAgIGFycmFuZ2UocGVyY2VudCkKICAKICAjIFRyYW5zZm9ybSBpbnRvIHpvbyBvYmplY3QgdG8gZmlsbCB0aGUgTkFzIHdpdGggaW50ZXJwb2xhdGVkIHZhbHVlcwogIHogPC0gcmVhZC56b28oZGF0YTIpICU+JSBuYS5hcHByb3ggJT4lCiAgIHRrX3RibChwcmVzZXJ2ZV9pbmRleD1UUlVFLCByZW5hbWVfaW5kZXg9ImluZGV4IikgJT4lCiAgIGZpbHRlcihpbmRleCAlaW4lIHNhbXBsZV9wb2ludHMkcGVyY2VudCkKICAKICByZXR1cm4oeikKfQoKIyBBbiBleGd0cmEgc3RlcCB0byBwcmVwIGdlc3R1cmUgZGF0YQojIENvbnZlcnQgdF9pbml0IGZvciBlYWNoIHBvaW50IHRvIGEgdmFsdWUgYmV0d2VlbiAwIHRvIDEgYmFzZWQgb24gdGhlIGxlbmd0aCBvZiB0aGUgZ2VzdHVyZQpwcmVwX2dlc3QgPC0gZnVuY3Rpb24oZ2VzdCkgewogIG1heF90aW1lIDwtdGFpbChnZXN0JHRfZW5kLCAxKQogIGdlc3QgPC0gZ2VzdCAlPiUgbXV0YXRlKHBlcmNlbnQ9dF9pbml0L21heF90aW1lKSAlPiUKICAgICAgICAgICAgICMgb25seSBrZWVwIGxvY2FsIHNjcnViIHRpbWUgYW5kIHRoZSBmcmVxIHZhbHVlcyAKICAgICAgICAgICAgIHNlbGVjdChwZXJjZW50LCBmKQogIHJldHVybihnZXN0KQp9CgpgYGAKCiMgTG9hZGluZyByZWZlcmVuY2UgcGl0Y2ggY3VydmVzCgpSZWZlcmVuY2VzIGNvbnRhaW4gaW5mb3JtYXRpb24gYWJvdXQgdGhlIHN0eWxpemVkIHBpdGNoIGN1cnZlIG9mIGEgcGhyYXNlLiBUaGUgc3R5bGl6YXRpb24gaXMgZG9uZSBieSBQcm9zb2dyYW0sIGFuIGV4dGVuc2lvbiB0byBQcmFhdCBiYXNlZCBvbiBhIHBlcmNlcHR1YWwgbW9kZWwgZGV0YWlsZWQgYnkgZCdBbGxlc3NhbmRybyBhbmQgTWVydGVucyAxOTk1LiBUaGUgc3R5bGl6YXRpb24gaXMgb3JpZ2luYWxseSBnZW5lcmF0ZWQgYXMgUGl0Y2hUaWVyIGZpbGVzIGJ5IFByb3NvZ3JhbSBidXQgYXJlIGNvbnZlcnRlZCB0byBKU09OIGJ5IFtTY3JpcHQgMzogcGl0Y2h0aWVyVG9KU09OXShub3RlYm9va3MvM19waXRjaHRpZXJUb0pTT04uUm1kKS4KClRoZSBjb2RlIGJlbG93IGxvYWRzIGFsbCB0aGUgYXZhaWxhYmxlIHJlZmVyZW5jZSBmaWxlcyBidXQgb25seSBsb29rcyBhdCB0aGUgZmlyc3Qgb25lIGFzIGEgdGVzdC4KCmBgYHtyLCBmaWcua2VlcD0nYWxsJywgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KCm51bV9zYW1wbGVzID0gMTAwCgpwYXRoPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9yZWZlcmVuY2UvIgpzZXR3ZChwYXN0ZTAocGF0aCwgInByb3NvZ3JhbV9wdCIpKQpyZWZfZmlsZW5hbWVzIDwtIGRpcihwYXR0ZXJuPSJcXC5qc29uJCIpCnJlZl9uYW1lIDwtIHJlZl9maWxlbmFtZXNbMV0KCiMgTmVlZCB0byBjaGFuZ2UgdG8gbm9ybWFsIHdvcmtpbmcgZGlyZWN0b3J5IGZvciBjb2RlIHRvIHdvcmsKc2V0d2QoIi4uLy4uLy4uLy4uLy4uL25vdGVib29rcy8iKQpyZWZfZGF0YSA8LSBmcm9tSlNPTihwYXN0ZTAocGF0aCwicHJvc29ncmFtX3B0LyIscmVmX25hbWUpKSAlPiUgYXNfdGliYmxlKCkgJT4lIAogICAgICAgICAgICAjIFRvIGF2b2lkIGNvbmZ1c2lvbiwgY3JlYXRlIG5ldyBjb2x1bW4gY2FsbGVkIHBlcmNlbnQKICAgICAgICAgICAgbXV0YXRlKHBlcmNlbnQgPSBzY3J1YikgJT4lIHNlbGVjdChwZXJjZW50LCBmKQoKcmVmX2ludGVycCA8LSBnZXRfaW50ZXJwb2xhdGVkX2RhdGEocmVmX2RhdGEsIG51bV9zYW1wbGVzKQpyZWZfdHMgPC0gcmVmX2ludGVycCR2YWx1ZQogCiMgUGxvdCByZXN1bHRzCmdncGxvdChkYXRhPXJlZl9kYXRhLCBhZXMoeD1wZXJjZW50LCB5PWYpKSArCiAgICAgIGdlb21fcG9pbnQoc2l6ZT0zLCBhZXMoY29sb3I9Ik9yaWdpbmFsIHBvaW50cyIpKSArCiAgICAgIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiRGF0YSBzb3VyY2UiKSArCiAgICAgIGdlb21fcG9pbnQoZGF0YT1yZWZfaW50ZXJwLCBhZXMoeD1pbmRleCwgeT12YWx1ZSwgY29sb3I9IkludGVycG9sYXRlZCIpLCBzaXplPTAuNTUpICsKICAgICAgbGFicyh0aXRsZT0iSW50ZXJwb2xhdGVkIHJlZmVyZW5jZSBwaXRjaCBjdXJ2ZSIsIAogICAgICAgICAgIHN1YnRpdGxlPXBhc3RlKCJQaHJhc2U6IixzdHJfc3BsaXQocmVmX25hbWUsICcuanNvbicpW1sxXV1bMV0pLAogICAgICAgICAgIHk9ImZyZXF1ZW5jeSAoc2VtaXRvbmVzIGZyb20gMTMwaHopIikKCiMgRmluYWxseSwgdGhlIHRpbWUgc2VyaWVzIGlzIHRoZSB2YWx1ZXMgdmVjdG9yCiMgVGhpcyB3aWxsIGJlIHVzZWQgaW4gdGhlIGNvbXBhcmlzb24gYWxnb3JpdGhtcwpyZWZfdHMgPC0gcmVmX2ludGVycCR2YWx1ZQoKYGBgCgojIyBMb2FkaW5nIGFsbCBwaHJhc2VzCgpOb3cgbGV0J3MgZG8gdGhlIHNhbWUgdGhpbmcgdG8gYWxsIHRoZSByZWZlcmVuY2UgZmlsZXMKCmBgYHtyfQojIE9yaWdpbmFsIGRhdGEgZm9yIGVhY2ggcmVmZXJlbmNlLCBpbiB0ZXJtcyBvZjoKIyBwZXJjZW50IDogcGVyY2VudGFnZSB0aW1lIChpLmUuIHNjcnViKQojIGYgOiBmcmVxdWVuY3kgaW4gU1Qgd2l0aCAxMzAgaHogcmVmZXJlbmNlCnJlZl9vcmlnaW5hbHMgPC0gbGFwcGx5KHJlZl9maWxlbmFtZXMsIGZ1bmN0aW9uKGVsdCkgewogIHJlc3VsdCA8LSBmcm9tSlNPTihwYXN0ZTAocGF0aCwicHJvc29ncmFtX3B0LyIsIGVsdCkpICU+JSBhc190aWJibGUoKSAlPiUgCiAgICAgICAgICAgICMgVG8gYXZvaWQgY29uZnVzaW9uLCBjcmVhdGUgbmV3IGNvbHVtbiBjYWxsZWQgcGVyY2VudAogICAgICAgICAgICBtdXRhdGUocGVyY2VudCA9IHNjcnViKSAlPiUgc2VsZWN0KHBlcmNlbnQsIGYpCn0pCgojIEludGVycG9sYXRlZCB0aW1lIHNlcmllcyBkYXRhIG9mIGp1c3QgdGhlIGYgdmFsdWVzCnJlZl90c3MgPC0gbGFwcGx5KHJlZl9vcmlnaW5hbHMsIGZ1bmN0aW9uKGVsdCkgewogIHJlZl9pbnRlcnA8LWdldF9pbnRlcnBvbGF0ZWRfZGF0YShlbHQsIG51bV9zYW1wbGVzKQogIHJlZl9pbnRlcnAkdmFsdWUKfSkKCiMgQSB2ZWN0b3Igd2l0aCBqdXN0IHRoZSBuYW1lcyBvZiB0aGUgcGhyYXNlcyAody9vIC5qc29uIGV4dGVuc2lvbikKcmVmX3BocmFzZXMgPC0gZG8uY2FsbCgicmJpbmQiLCBsYXBwbHkocmVmX2ZpbGVuYW1lcywgZnVuY3Rpb24oZWx0KSB7CiAgc3RyX3NwbGl0KGVsdCwgJy5qc29uJylbWzFdXVsxXQp9KSlbLDFdCgojIFJldHVybnMgdGhlIHJlZmVyZW5jZSB0aW1lIHNlcmllcyBmIHZhbHVlcyBnaXZlbiB0aGUgcGhyYXNlIG5hbWUKZ2V0X3JlZl90cyA8LSBmdW5jdGlvbihwaHJhc2VfbmFtZSkgewogIGluZGV4IDwtIG1hdGNoKHBocmFzZV9uYW1lLCByZWZfcGhyYXNlcykKICBpZiAoaXMubmEoaW5kZXgpKSB7IHJldHVybihOVUxMKSB9CiAgcmV0dXJuKHJlZl90c3NbW2luZGV4XV0pCn0KYGBgCgoKIyBMb2FkaW5nIGdlc3R1cmVzCgpUaGUgZ2VzdHVyZXMgYXJlIGNvbGxlY3RlZCBmcm9tIG5vbi1uYXRpdmUgc3BlYWtlcnMgZW5yb2xsZWQgaW4gYSBjbGFzcyBvbiBGcmVuY2ggcmh5dGhtIGFuZCBpbnRvbmF0aW9uLiBGaXJzdCwganVzdCBsb2FkIGFuZCBwbG90IG9uZSBnZXN0dXJlIGFzIGEgdGVzdC4KClRoZSByZXN1bHRpbmcgZ2VzdHVyZSBpcyBwbG90dGVkIHdpdGggaXRzIHJlZmVyZW5jZSBvdmVybGFpZC4gSW4gdGhpcyBhbmFseXNpcywgdGhlIHBob25lbWVzIG9mIHRoZSBnZXN0dXJlIGFyZSBub3QgYWxpZ25lZCB3aXRoIHRob3NlIG9mIHRoZSByZWZlcmVuY2UuIEl0J3MgCgpgYGB7ciwgZmlnLmtlZXA9J2FsbCcsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgTG9hZCBmaXJzdCBnZXN0dXJlCnBhdGg9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2dlc3R1cmVzLyIKc2V0d2QocGF0aCkKZ2VzdF9maWxlbmFtZXMgPC0gZGlyKHBhdHRlcm49IlxcLmdlc3QkIikKbmFtZSA8LSBnZXN0X2ZpbGVuYW1lc1sxXQpzZXR3ZCgiLi4vLi4vLi4vLi4vbm90ZWJvb2tzLyIpCmdlc3RfZGF0YSA8LSBmcm9tSlNPTihwYXN0ZTAocGF0aCwgbmFtZSkpICU+JSBhc190aWJibGUoKQoKZ2VzdF9kYXRhX2ludGVycCA8LSBnZXRfaW50ZXJwb2xhdGVkX2RhdGEocHJlcF9nZXN0KGdlc3RfZGF0YSksIG51bV9zYW1wbGVzKQoKIyBQbG90IHJlc3VsdHMKIyBEb3R0ZWQgaXMgcmVmZXJlbmNlCmdncGxvdChkYXRhPWdlc3RfZGF0YV9pbnRlcnAsIGFlcyh4PWluZGV4LCB5PXZhbHVlLCBjb2xvcj0iZ2VzdHVyZSIpKSArIAogICAgICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIkRhdGEgc291cmNlIikgKwogICAgICBnZW9tX3BvaW50KHNpemU9MC41KSArIAogICAgICBnZW9tX3BvaW50KGRhdGE9cmVmX2ludGVycCwgYWVzKHg9aW5kZXgsIHk9dmFsdWUsIGNvbG9yPSJyZWZlcmVuY2UiKSwgc2l6ZT0wLjUpICsKICAgICAgbGFicyh0aXRsZT0iQSBnZXN0dXJlIGFuZCBpdHMgcmVmZXJlbmNlIiwgCiAgICAgICAgICAgc3VidGl0bGU9cGFzdGUoIlBocmFzZToiLHN0cl9zcGxpdChyZWZfbmFtZSwgJy5qc29uJylbWzFdXVsxXSksCiAgICAgICAgICAgeT0iZnJlcXVlbmN5IChzZW1pdG9uZXMgZnJvbSAxMzBoeikiLAogICAgICAgICAgIHg9InBlcmNlbnQiKQoKCiMgRmluYWxseSwgdGhlIHRpbWUgc2VyaWVzIGlzIHRoZSB2YWx1ZXMgdmVjdG9yCiMgVGhpcyB3aWxsIGJlIHVzZWQgaW4gdGhlIGNvbXBhcmlzb24gYWxnb3JpdGhtcwpnZXN0X3RzIDwtIGdlc3RfZGF0YV9pbnRlcnAkdmFsdWUKCmBgYAoKIyMgTG9hZGluZyBhbGwgZ2VzdHVyZXMKCk5vdywgY29udmVydCBhbGwgdGhlIGdlc3R1cmVzIGludG8gdGltZSBzZXJpZXMuCgpgYGB7cn0KIyBPcmlnaW5hbCBkYXRhIGZvciBlYWNoIGdlc3R1cmUsIGluIHRlcm1zIG9mOgojIHBlcmNlbnQgOiBwZXJjZW50YWdlIHRpbWUgKGkuZS4gc2NydWIpCiMgZiA6IGZyZXF1ZW5jeSBpbiBTVCB3aXRoIDEzMCBoeiByZWZlcmVuY2UKZ2VzdF9vcmlnaW5hbHMgPC0gbGFwcGx5KGdlc3RfZmlsZW5hbWVzLCBmdW5jdGlvbihlbHQpIHsKICByZXN1bHQgPC0gZnJvbUpTT04ocGFzdGUwKHBhdGgsIGVsdCkpICU+JSBhc190aWJibGUoKSAlPiUgCiAgICAjIE5PVEUgVEhJUyBFWFRSQSBTVEVQICAgICAgCiAgICBwcmVwX2dlc3QoKQp9KQoKIyBJbnRlcnBvbGF0ZWQgdGltZSBzZXJpZXMgZGF0YSBvZiBqdXN0IHRoZSBmIHZhbHVlcwpnZXN0X3RzcyA8LSBsYXBwbHkoZ2VzdF9vcmlnaW5hbHMsIGZ1bmN0aW9uKGVsdCkgewogIGdlc3RfaW50ZXJwPC1nZXRfaW50ZXJwb2xhdGVkX2RhdGEoZWx0LCBudW1fc2FtcGxlcykKICBnZXN0X2ludGVycCR2YWx1ZQp9KQoKIyBSZXR1cm5zIHRoZSBnZXN0dXJlIHRpbWUgc2VyaWVzIGYgdmFsdWVzIGdpdmVuIHRoZSBwaHJhc2UgbmFtZQpnZXRfZ2VzdF90cyA8LSBmdW5jdGlvbihnZXN0X25hbWUpIHsKICBpbmRleCA8LSBtYXRjaChnZXN0X25hbWUsIGdlc3RzKQogIGlmIChpcy5uYShpbmRleCkpIHsgcmV0dXJuKE5VTEwpIH0KICByZXR1cm4oZ2VzdF90c3NbW2luZGV4XV0pCn0KCmBgYAoKCiMgVGVzdGluZyBjb21wYXJpc29uIGZ1bmN0aW9ucwoKTm93IHdlIGFyZSByZWFkeSB0byBxdWFudGl0YXRpdmVseSBjb21wYXJlIGEgZ2VzdHVyZSBhbmQgaXRzIHJlZmVyZW5jZS4gT25lIG1ldGhvZCBpcyBQZWFyc29uJ3MgQ29ycmVsYXRpb24sIHdoaWNoIGNoZWNrJ3MgdGhlIHNpbWlsYXJpdHkgYmV0d2VlbiB0aGUgdHdvIGN1cnZlcy4gQSB2YWx1ZSBvZiAxIG1lYW5zIGlkZW50aWNhbCBjdXJ2ZXMuIE5vdGUgdGhhdCB0aGUgbWVhbiBpcyBzdWJ0cmFjdGVkIGZyb20gZWFjaCBjdXJ2ZSwgc28gbGFyZ2VyIGdhcHMgYmV0d2VlbiB0aGUgY3VydmVzIHNob3VsZCBub3QgZGVjcmVhc2UgdGhlIGNvcnJlbGF0aW9uIHZhbHVlLgoKJHIgPSBcZnJhY3t7fVxzdW1fe2k9MX1ee259ICh4X2kgLSBcb3ZlcmxpbmV7eH0pKHlfaSAtIFxvdmVybGluZXt5fSl9IHtcc3FydHtcc3VtX3tpPTF9XntufSAoeF9pIC0gXG92ZXJsaW5le3h9KV4yKHlfaSAtIFxvdmVybGluZXt5fSleMn19JAoKQW5vdGhlciBtZXRob2QgaXMgUm9vdCBNZWFuIFNxdWFyZSBFcnJvciAoUk1TKSwgd2hpY2ggbWVhbnN1cmVzIHRoZSBkaXNzaW1pbmxhcml0eSBiZXR3ZWVuIHRoZSB0d28gY3VydmVzLiBUaGUgaGlnaGVyIHRoZSBudW1iZXIgbWVhbnMgdGhlcmUgaXMgbW9yZSBkaWZmZXJlbmNlLgoKJCBSTVMgPSBcc3FydHsgXHN1bV97aT0xfV57bn0gKCh4X2kgLSBcb3ZlcmxpbmV7eH0pIC0gKHlfaSAtIFxvdmVybGluZXt5fSkpXjIgKSB9ICQKCkluIHRoZSAyMDExIHBhcGVyIGV2YWx1YXRpbmcgY2hpcm9ub215LCBib3RoIG9mIHRoZXNlIG1lYXN1cmVzIGFyZSB3ZWlnaGVkIGJ5IHRoZSBpbnRlbnNpdHkgb2YgdGhlIHJlZmVyZW5jZSBhdWRpby4gRm9yIG5vdyBJJ20gbGVhdmluZyB0aGF0IHdlaWdodGluZyBvdXQuCgoKYGBge3J9CmNvcihyZWZfdHMsIGdlc3RfdHMsICBtZXRob2QgPSAicGVhcnNvbiIpCmBgYAoKYGBge3J9CnJtc2UgPC0gZnVuY3Rpb24oYSwgYikgewogIHJldHVybihzcXJ0KHN1bSggKChhLW1lYW4oYSkpIC0gKGItbWVhbihiKSkpIF4yICkpKQp9CgpybXNlKHJlZl90cywgZ2VzdF90cykKYGBgCgoKIyMgQ2FsY3VsYXRpbmcgY29tcGFyaXNvbiBmdW5jdGlvbnMgZm9yIGFsbCBnZXN0dXJlcwoKYGBge3J9CgojIEEgdmVjdG9yIHdpdGgganVzdCB0aGUgbmFtZXMgb2YgdGhlIHBocmFzZXMgKHcvbyAuanNvbiBleHRlbnNpb24pCmdlc3RzIDwtIGRvLmNhbGwoInJiaW5kIiwgbGFwcGx5KGdlc3RfZmlsZW5hbWVzLCBmdW5jdGlvbihlbHQpIHsKICBzdHJfc3BsaXQoZWx0LCAnLmdlc3QnKVtbMV1dWzFdCn0pKVssMV0KCiMgSnVzdCB0aGUgbmFtZSBvZiBzdWJqZWN0cwpnZXN0X3N1YmplY3RzIDwtIGRvLmNhbGwoInJiaW5kIiwgbGFwcGx5KGdlc3RzLCBmdW5jdGlvbihlbHQpIHsKICB0YWlsKHN0cl9zcGxpdChlbHQsICctJylbWzFdXSwgMSkKfSkpWywxXQojIEp1c3QgdGhlIG5hbWUgb2YgcGhyYXNlcwpnZXN0X3BocmFzZXMgPC0gZG8uY2FsbCgicmJpbmQiLCBsYXBwbHkoZ2VzdHMsIGZ1bmN0aW9uKGVsdCkgewogIHN0cl9zcGxpdChlbHQsICctJylbWzFdXQp9KSlbLDFdCgojIEV4dHJhY3QgdGhlIHJlZmVyZW5jZSBwaHJhc2UgZnJvbSB0aGUgd2hvbGUgZ2VzdHVyZSBuYW1lCmdldF9yZWZfbmFtZSA8LSBmdW5jdGlvbihnZXN0X25hbWUpIHsKICByZXR1cm4oc3RyX3NwbGl0KGdlc3RfbmFtZSwgJy0nKVtbMV1dWzFdKQp9CgojIENvbXB1dGUgdGhlIGNvcnJlbGF0aW9uIGFuZCBybXMgZ2l2ZW4gdGhlIGVudGlyZSBnZXN0dXJlIG5hbWUKZ2V0X2NvcnIgPC0gZnVuY3Rpb24oZ2VzdF9uYW1lKSB7CiAgcmVmX3RzIDwtIGdldF9yZWZfdHMoZ2V0X3JlZl9uYW1lKGdlc3RfbmFtZSkpCiAgZ2VzdF90cyA8LSBnZXRfZ2VzdF90cyhnZXN0X25hbWUpCiAgcmV0dXJuKGNvcihyZWZfdHMsIGdlc3RfdHMsIG1ldGhvZD0icGVhcnNvbiIpKQp9CgpnZXRfcm1zIDwtIGZ1bmN0aW9uKGdlc3RfbmFtZSkgewogIHJlZl90cyA8LSBnZXRfcmVmX3RzKGdldF9yZWZfbmFtZShnZXN0X25hbWUpKQogIGdlc3RfdHMgPC0gZ2V0X2dlc3RfdHMoZ2VzdF9uYW1lKQogIHJldHVybihybXNlKHJlZl90cywgZ2VzdF90cykpCn0KCmNvcnJfYWxsIDwtIGRvLmNhbGwoInJiaW5kIiwgbGFwcGx5KGdlc3RzLCBmdW5jdGlvbihlbHQpIHsKICBnZXRfY29ycihlbHQpCn0pKVssMV0KCnJtc2VfYWxsIDwtIGRvLmNhbGwoInJiaW5kIiwgbGFwcGx5KGdlc3RzLCBmdW5jdGlvbihlbHQpIHsKICBnZXRfcm1zKGVsdCkKfSkpWywxXQoKIyBDb21iaW5lIHRoZSBhYm92ZSB2ZWN0b3JzIGludG8gYSB0aWJibGUKZ2VzdF90aWJibGUgPC0gdGliYmxlKGdlc3Q9Z2VzdHMsIGNvcnI9Y29ycl9hbGwsIHJtc2U9cm1zZV9hbGwpCnByaW50KGFzLm1hdHJpeChnZXN0X3RpYmJsZSksIHF1b3RlID0gRkFMU0UpCmBgYAoKIyMgUGxvdHRpbmcKCkxldCBzZWUgaWYgb3VyIG51bWJlcnMgbWFrZSBzZW5zZS4gSW4gQ2hyaXN0b3BoZSdzIHByZXZpb3VzIGV2YWx1YXRpb24sIHRoZXkgcHJpbWFyaWx5IGxvb2tlZCBhdCB0aGUgY29ycmVsYXRpb24gdmFsdWUgYW5kIG9ubHkgbG9va2VkIGF0IHRoZSBSTVMgaWYgdGhlIGNvcnJlbGF0aW9uIHdhcyB0aGUgc2FtZSBmb3IgdHdvIHN0aW11bGkuCgpgYGB7cn0KCnBsb3RfZ2VzdF9hbmRfcmVmIDwtIGZ1bmN0aW9uKGdlc3RfbmFtZSkgewogIHJlZl9waHJhc2UgPC0gZ2V0X3JlZl9uYW1lKGdlc3RfbmFtZSkKICByZWZfdHMgPC0gZ2V0X3JlZl90cyhyZWZfcGhyYXNlKQogIGdlc3RfdHMgPC0gZ2V0X2dlc3RfdHMoZ2VzdF9uYW1lKQogIAogIHJvdyA8LSBmaWx0ZXIoZ2VzdF90aWJibGUsIGdlc3Q9PWdlc3RfbmFtZSkKICBjb3JyIDwtIHJvdW5kKHJvdyRjb3JyLCA0KQogIHJtc2UgPC0gcm91bmQocm93JHJtc2UsIDQpCiAgCiAgbXlfZGF0YSA8LSB0aWJibGUoZ2VzdD1nZXN0X3RzLCByZWY9cmVmX3RzLCBwZXJjZW50PXNlcSgwLCAxLCBsZW5ndGgub3V0PW51bV9zYW1wbGVzKSkKICAKICBteV9wbG90IDwtIGdncGxvdChkYXRhPW15X2RhdGEsIGFlcyh4PXBlcmNlbnQsIHk9Z2VzdCwgY29sb3I9Imdlc3R1cmUiKSkgKwogICAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJEYXRhIHNvdXJjZSIpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpICsKICAgIGdlb21fcG9pbnQoZGF0YT1teV9kYXRhLCBhZXMoeD1wZXJjZW50LCB5PXJlZiwgY29sb3I9InJlZmVyZW5jZSIpLCBzaXplPTAuNSkgKwogICAgbGFicyh0aXRsZT1wYXN0ZShnZXN0X25hbWUsICJ3aXRoIGl0cyByZWZlcmVuY2UiKSwgCiAgICAgICAgICAgIHN1YnRpdGxlPXBhc3RlKCJDb3JyOiIsIGNvcnIsICJSTVNFOiIsIHJtc2UpLAogICAgICAgICAgICB5PSJmcmVxdWVuY3kgKHNlbWl0b25lcyBmcm9tIDEzMGh6KSIsCiAgICAgICAgICAgIHg9InBlcmNlbnQgdGltZSIpCiAgcmV0dXJuKG15X3Bsb3QpCn0KCiMgUGxvdCBldmVyeXRoaW5nIGFuZCBzdG9yZSBwbG90cyBpbiBhIGxpc3QKcGxvdHNfYWxsPC1sYXBwbHkoZ2VzdHMsIHBsb3RfZ2VzdF9hbmRfcmVmKQpgYGAKCk5vdywgbGV0J3MgZGl2aWRlIHRoZSBnZXN0dXJlcyBieSBzY29yZSByYW5nZXMgYW5kIHBsb3QgdGhlbS4gVGhlcmUgYXJlIHNvbWUgZXhjZXB0aW9ucyBmb3IgdGhlIG1pZCB2YWx1ZXMsIGJ1dCBpbiBnZW5lcmFsLCB0aGUgaGlnaGVzdCBzY29yaW5nIGdlc3R1cmVzIGFyZSB0aGUgbW9zdCBhY2N1cmF0ZSBhbmQgdGhlIGxvd2VzdCBzY29yaW5nIHRoZSBsZWFzdCBhY2N1cmF0ZS4KCiMjIyBIaWdoZXN0IHNjb3JpbmcgZ2VzdHVyZXMgKD4gMC45KQoKYGBge3IsIGZpZy5rZWVwPSdhbGwnfQpwbG90c19hbGxbWzddXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMTNfbGFfYmVsbGVfZmVybWVfbGVfdm9pbGUtYzIubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzEzX2xhX2JlbGxlX2Zlcm1lX2xlX3ZvaWxlLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpBIHZpc3VhbCBndWlkZSB3YXMgZGlzcGxheWVkIGZvciB0aGlzIHRyaWFsLgoKPGJyLz4KCmBgYHtyLCBmaWcua2VlcD0nYWxsJ30KcGxvdHNfYWxsW1s5XV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzEzYmlzX2xhX2JlbGxlX2Zlcm1lX19sZV92b2lsZS1nMi5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMTNiaXNfbGFfYmVsbGVfZmVybWVfX2xlX3ZvaWxlLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpBIHZpc3VhbCBndWlkZSB3YXMgZGlzcGxheWVkIGZvciB0aGlzIHRyaWFsLgoKPGJyLz4KCmBgYHtyLCBmaWcua2VlcD0nYWxsJ30KcGxvdHNfYWxsW1sxM11dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yX3R1X3BhcmFpc190cmVzX3NvdWNpZXV4LWJfcy5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMl90dV9wYXJhaXNfdHJlc19zb3VjaWV1eC5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKQSB2aXN1YWwgZ3VpZGUgd2FzIG5vdCBkaXNwbGF5ZWQgZm9yIHRoaXMgdHJpYWwuIFRoaXMgb25lIGlzIHVubWlzdGFrYWJseSBwcm9ub3VuY2luZyB0aGUgY29ycmVjdCBwaHJhc2UsIGJ1dCBpdCBzb3VuZHMgbGlrZSBpdCBoYXMgYSBiaXQgb2YgYW4gYWNjZW50LgoKPGJyLz4KCiMjIyBIaWdoaXNoIHNjb3JlcyAoLjcgdG8gLjkpCgpgYGB7cn0KcGxvdHNfYWxsW1syXV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzFfSWxfbmFpdF90cmVzX3ByZW1hdHVyZS1iX20ubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzFfSWxfbmFpdF90cmVzX3ByZW1hdHVyZS5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKU291bmRzIGNvcnJlY3QgdG8gbWUuCgo8YnIvPgoKYGBge3J9CnBsb3RzX2FsbFtbNV1dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8xMGJpc19qZW5zZWlnbmVfYmVhdWNvdXAtbDIubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzEwYmlzX2plbnNlaWduZV9iZWF1Y291cC5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKU291bmRzIGNvcnJlY3QgdG8gbWUuCgo8YnIvPgoKYGBge3J9CnBsb3RzX2FsbFtbMTFdXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMWJpc19JbF9uYWl0cmFpdF9wcmVtYXR1cmUtYl9nLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpPcmlnaW5hbCA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8xYmlzX0lsX25haXRyYWl0X3ByZW1hdHVyZS5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKU291bmRzIGNvcnJlY3QgYnV0IGEgYml0IG9kZC4KCjxici8+CgpgYGB7cn0KcGxvdHNfYWxsW1sxMl1dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yX3R1X3BhcmFpc190cmVzX3NvdWNpZXV4LWFfYy5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMl90dV9wYXJhaXNfdHJlc19zb3VjaWV1eC5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKU291bmRzIGNvcnJlY3QgYnV0IHRoZSByaHl0aG0gaXMgcXVpdGUgb2ZmCgo8YnIvPgoKYGBge3J9CnBsb3RzX2FsbFtbMThdXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjBiaXNfamVhbnBpZXJyZV9ldF9qYWNxdWVzLXkyLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpPcmlnaW5hbCA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yMGJpc19qZWFucGllcnJlX2V0X2phY3F1ZXMubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KClNvdW5kcyBjb3JyZWN0IHRvIG1lLgoKPGJyLz4KCmBgYHtyfQpwbG90c19hbGxbWzIwXV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzI3X2xhX2Jvbm5lX19jdWlzaW5lX2F2ZWNfZGVzX25hdmV0cy12Mi5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjdfbGFfYm9ubmVfX2N1aXNpbmVfYXZlY19kZXNfbmF2ZXRzLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpTb3VuZHMgY29ycmVjdCB0byBtZS4KCjxici8+CgpgYGB7cn0KcGxvdHNfYWxsW1syM11dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yN2Jpc19sYV9ib25uZV9jdWlzaW5lX19hdmVjX2Rlc19uYXZldHMtbTIubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzI3YmlzX2xhX2Jvbm5lX2N1aXNpbmVfX2F2ZWNfZGVzX25hdmV0cy5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKU291bmRzIGEgYml0IHdlaXJkIHdpdGggcmh5dGhtIGluIHRoZSBlbmQuCgo8YnIvPgoKYGBge3J9CnBsb3RzX2FsbFtbMjRdXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjdiaXNfbGFfYm9ubmVfY3Vpc2luZV9fYXZlY19kZXNfbmF2ZXRzLW0zLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpPcmlnaW5hbCA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yN2Jpc19sYV9ib25uZV9jdWlzaW5lX19hdmVjX2Rlc19uYXZldHMubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KClNvdW5kcyBjb3JyZWN0IHRvIG1lLgoKPGJyLz4KCiMjIyBNaWRpc2ggc2NvcmVzICguNSB0byAuNykKCmBgYHtyfQpwbG90c19hbGxbWzE1XV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzIwX2plYW5fcGllcnJlX2V0X2phY3F1ZXMtczIubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzIwX2plYW5fcGllcnJlX2V0X2phY3F1ZXMubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCldpdGggdmlzdWFsIGd1aWRlLiBTb3VuZHMgY29ycmVjdCB0byBtZS4KCjxici8+CgoKYGBge3J9CnBsb3RzX2FsbFtbMTZdXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjBfamVhbl9waWVycmVfZXRfamFjcXVlcy1zMy5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjBfamVhbl9waWVycmVfZXRfamFjcXVlcy5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKV2l0aCB2aXN1YWwgZ3VpZGUuIFNvdW5kcyBjb3JyZWN0LgoKPGJyLz4KCmBgYHtyfQpwbG90c19hbGxbWzIxXV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzI3X2xhX2Jvbm5lX19jdWlzaW5lX2F2ZWNfZGVzX25hdmV0cy12My5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjdfbGFfYm9ubmVfX2N1aXNpbmVfYXZlY19kZXNfbmF2ZXRzLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpXaXRoIHZpc3VhbCBndWlkZS4gU291bmRzIGEgYml0IGFtYmlndW91cy4KCjxici8+CgoKYGBge3J9CnBsb3RzX2FsbFtbMjVdXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMmJpc190dV9wYXJhaXRyYWlzX3NvdWNpZXV4LWFfZy5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMmJpc190dV9wYXJhaXRyYWlzX3NvdWNpZXV4Lm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpXaXRob3V0IHZpc3VhbCBndWlkZS4gTW9zdCBsaWtlbHkgY29ycmVjdCBidXQgY291bGQgYmUgYSBiaXQgYW1iaWd1b3VzLgoKPGJyLz4KCiMjIyBMb3dpc2ggc2NvcmVzICguMyB0byAuNSkKYGBge3J9CnBsb3RzX2FsbFtbMV1dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8xX0lsX25haXRfdHJlc19wcmVtYXR1cmUtYV9jLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpPcmlnaW5hbCA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8xX0lsX25haXRfdHJlc19wcmVtYXR1cmUubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCldpdGhvdXQgdmlzdWFsIGd1aWRlLiBTb3VuZHMgY29ycmVjdCB0byBtZS4KCjxici8+CgoKYGBge3J9CnBsb3RzX2FsbFtbNF1dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8xMGJpc19qZW5zZWlnbmVfYmVhdWNvdXAtbDEubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzEwYmlzX2plbnNlaWduZV9iZWF1Y291cC5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKV2l0aG91dCB2aXN1YWwgZ3VpZGUuIENvdWxkIGJlIGhlYXJkIGFzIGNvcnJlY3QgcGhyYXNlIGJ1dCBhbWJpZ3VvdXMuCgo8YnIvPgoKCmBgYHtyfQpwbG90c19hbGxbWzE5XV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzI3X2xhX2Jvbm5lX19jdWlzaW5lX2F2ZWNfZGVzX25hdmV0cy12MS5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjdfbGFfYm9ubmVfX2N1aXNpbmVfYXZlY19kZXNfbmF2ZXRzLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpXaXRob3V0IHZpc3VhbCBndWlkZS4gU291bmRzIHZlcnkgYW1iaWd1b3VzLgoKPGJyLz4KCgpgYGB7cn0KcGxvdHNfYWxsW1syNl1dCmBgYAoKR2VzdHVyZSA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yYmlzX3R1X3BhcmFpdHJhaXNfc291Y2lldXgtYl95Lm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpPcmlnaW5hbCA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yYmlzX3R1X3BhcmFpdHJhaXNfc291Y2lldXgubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCldpdGhvdXQgdmlzdWFsIGd1aWRlLiBTb3VuZHMgaW5jb3JyZWN0IG9yIGFtYmlndW91cy4KCjxici8+CgojIyMgTG93ZXN0IHNjb3Jlcyg8IDApCgpgYGB7cn0KcGxvdHNfYWxsW1szXV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzEwX2plYW5fc2FpZ25lX2JlYXVjb3VwLWFfbS5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMTBfamVhbl9zYWlnbmVfYmVhdWNvdXAubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCkEgdmlzdWFsIGd1aWRlIHdhcyBub3QgZGlzcGxheWVkIGZvciB0aGlzIHRyaWFsLiBUaGUgZ2VzdHVyZSBzb3VuZHMgbGlrZSB0aGUgb3RoZXIgbWVhbmluZyBvZiB0aGUgcGhyYXNlLgoKPGJyLz4KCmBgYHtyfQpwbG90c19hbGxbWzEwXV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzFiaXNfSWxfbmFpdHJhaXRfcHJlbWF0dXJlLWFfeS5tcDMiIHR5cGU9ImF1ZGlvL21wMyI+CjwvYXVkaW8+PC9odG1sPgoKT3JpZ2luYWwgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMWJpc19JbF9uYWl0cmFpdF9wcmVtYXR1cmUubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCkEgdmlzdWFsIGd1aWRlIHdhcyBub3QgZGlzcGxheWVkIGZvciB0aGlzIHRyaWFsLiBJIHRoaW5rIHRoaXMgd291bGQgc3RpbGwgYmUgaGVhcmQgYXMgdGhlIGNvcnJlY3QgcGhyYXNlLCBidXQgaXRzIGludG9uYXRpb24gZGV2aWF0ZXMgZW5vcm1vdXNseSBmcm9tIHRoZSB0YXJnZXQuCgo8YnIvPgoKYGBge3J9CnBsb3RzX2FsbFtbMTddXQpgYGAKCkdlc3R1cmUgPGh0bWw+PGF1ZGlvIGNvbnRyb2xzPgo8c291cmNlIHNyYz0iLi4vZGF0YS8yMF8xMl8xNS1waWxvdF9nZXN0dXJlcy9hbWJpZ3VvdXMvYXVkaW8vMjBiaXNfamVhbnBpZXJyZV9ldF9qYWNxdWVzLXkxLm1wMyIgdHlwZT0iYXVkaW8vbXAzIj4KPC9hdWRpbz48L2h0bWw+CgpPcmlnaW5hbCA8aHRtbD48YXVkaW8gY29udHJvbHM+Cjxzb3VyY2Ugc3JjPSIuLi9kYXRhLzIwXzEyXzE1LXBpbG90X2dlc3R1cmVzL2FtYmlndW91cy9hdWRpby8yMGJpc19qZWFucGllcnJlX2V0X2phY3F1ZXMubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCkEgdmlzdWFsIGd1aWRlIHdhcyBub3QgZGlzcGxheWVkIGZvciB0aGlzIHRyaWFsLiBUaGUgZ2VzdHVyZSBzb3VuZHMgcXVpdGUgYW1iaWd1b3VzLiBDb3VsZCBzb21ldGltZXMgZ2V0IGhlYXJkIGluY29ycmVjdGx5LgoKPGJyLz4KCmBgYHtyfQpwbG90c19hbGxbWzE0XV0KYGBgCgpHZXN0dXJlIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzIwX2plYW5fcGllcnJlX2V0X2phY3F1ZXMtczEubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCk9yaWdpbmFsIDxodG1sPjxhdWRpbyBjb250cm9scz4KPHNvdXJjZSBzcmM9Ii4uL2RhdGEvMjBfMTJfMTUtcGlsb3RfZ2VzdHVyZXMvYW1iaWd1b3VzL2F1ZGlvLzIwX2plYW5fcGllcnJlX2V0X2phY3F1ZXMubXAzIiB0eXBlPSJhdWRpby9tcDMiPgo8L2F1ZGlvPjwvaHRtbD4KCkEgdmlzdWFsIGd1aWRlIHdhcyBub3QgZGlzcGxheWVkIGZvciB0aGlzIHRyaWFsLiBEZXNwaXRlIHRoZSBsb3cgY29ycmVsYXRpb24gc2NvcmUsIEkgdGhpbmsgdGhpcyBwaHJhc2Ugd291bGQgcHJvYmFibHkgYmUgaGVhcmQgY29ycmVjdGx5LgoKPGJyLz4K